package admin

import (
	"fmt"
	"go-amis-admin/amis"
	"go-amis-admin/utils"
	"html/template"
	"reflect"
	"sort"
	"strings"

	"github.com/gin-gonic/gin"
)

type Site struct {
	Label    string           `json:"label,omitempty"`
	Name     string           `json:"name,omitempty"`
	Sort     uint             `json:"sort,omitempty"`
	Template string           `json:"-"`
	Router   *gin.RouterGroup `json:"-"`
	Modules  []IModule        `json:"children,omitempty"`
	theme    []string
}

func NewSite(label, name, tpl string, sort uint, router *gin.RouterGroup) *Site {
	site := &Site{
		Label:    label,
		Name:     name,
		Sort:     sort,
		Template: tpl,
		Router:   router,
		theme:    []string{"cxd", "sdk"},
	}
	site.Router.Use(JwtAuthMiddleware())
	site.Router.GET("/", Handler(site.Index))
	site.Router.GET("menu", Handler(site.Menu))
	site.Router.GET("permList", Handler(site.PermTree))
	site.Router.GET("changeTheme", Handler(site.ChangeTheme))
	return site
}

func (s *Site) Index(ctx *AdminContext) {
	tpl, err := template.New("index.html").Parse(amis.IndexTpl)
	if err != nil {
		ctx.Fail(err.Error())
		return
	}
	var ret strings.Builder
	err = tpl.Execute(&ret, gin.H{
		"theme":    s.theme[0],
		"themeCss": s.theme[1],
		"title":    Instance.Config.Server.Title,
		"logo":     Instance.Config.Server.Logo,
	})
	if err != nil {
		ctx.Fail(err.Error())
		return
	}
	ctx.Header("Content-Type", "text/html")
	ctx.String(200, ret.String())
}

func (s *Site) Menu(ctx *AdminContext) {
	user := ctx.CurrentUser()
	resources := make([]Resource, 0)
	for _, module := range s.Modules {
		res := module.GetResource()
		res.Children = make([]Resource, 0)
		if floder, ok := module.(IFloder); ok {
			for _, module2 := range floder.GetChildren() {
				res2 := module2.GetResource()
				if ok, err := Instance.Auth.HasPermissionForUser(
					fmt.Sprintf("%d", user.RoleID),
					res2.Name, "view"); ok && err == nil || user.ID == 1 {
					res.Children = append(res.Children, res2)
				}
			}
		} else {
			if ok, err := Instance.Auth.HasPermissionForUser(
				fmt.Sprintf("%d", user.RoleID),
				res.Name, "view"); ok && err == nil || user.ID == 1 {
			}
		}
		sort.Slice(res.Children, func(i, j int) bool {
			return res.Children[i].Sort < res.Children[j].Sort
		})
		resources = append(resources, res)
		sort.Slice(resources, func(i, j int) bool {
			return resources[i].Sort < resources[j].Sort
		})
	}
	ctx.Sucess(gin.H{"pages": amis.Obj{"label": s.Label, "children": resources}}, "success")
}

func (s *Site) ChangeTheme(ctx *AdminContext) {
	theme := ctx.Query("theme")
	if theme == "" {

		ctx.Fail("参数错误")
		return
	}
	// todo 持久化个人配置
	s.theme = strings.Split(theme, ",")
	ctx.Sucess(nil, "success")
}

// 模块资源挂载
func (s *Site) Mount(modules ...IModule) {
	s.Modules = append(s.Modules, modules...)
	s.register(modules)
}

func (s *Site) register(modules []IModule) {
	for _, srv := range modules {
		if floder, ok := srv.(IFloder); ok {
			s.register(floder.GetChildren())
			continue
		}
		t := reflect.TypeOf(srv)
		numMethods := t.NumMethod()
		for i := 0; i < numMethods; i++ {
			method := t.Method(i)
			mv := reflect.ValueOf(srv)
			funcValue := mv.Method(i)
			funcType := funcValue.Type()
			if funcType.NumIn() == 1 && funcType.In(0).Kind() == reflect.Ptr && funcType.In(0).Elem().Name() == "AdminContext" {
				name := utils.LowerFirstLetter(method.Name)
				if strings.HasSuffix(method.Name, "Api") {
					name = strings.TrimSuffix(name, "Api")
					if strings.HasPrefix(method.Name, "Get") {
						s.Router.GET(srv.GetRouterPath(name), Handler(funcValue.Interface().(func(*AdminContext))))
					} else if strings.HasPrefix(method.Name, "Put") {
						s.Router.PUT(srv.GetRouterPath(name), Handler(funcValue.Interface().(func(*AdminContext))))
					} else if strings.HasPrefix(method.Name, "Delete") {
						s.Router.DELETE(srv.GetRouterPath(name), Handler(funcValue.Interface().(func(*AdminContext))))
					} else {
						s.Router.POST(srv.GetRouterPath(name), Handler(funcValue.Interface().(func(*AdminContext))))
					}
				} else if strings.HasSuffix(method.Name, "View") {
					s.Router.GET(srv.GetRouterPath(name), Handler(funcValue.Interface().(func(*AdminContext))))
				} else {
					// todo 不符合命名规范的接口
				}
			}
		}

	}
}

func (s *Site) initModule() {
	Instance.DB.AutoMigrate(&User{}, &DicType{}, &DicDetail{}, &Department{})
	// 创建服务
	var userservice = NewUserModule(s.Router.BasePath())
	var dictService = NewDictModule(s.Router.BasePath())
	var roleModule = NewRoleModule(s.Router.BasePath())
	var dashboard = NewDashboard(s.Router.BasePath())
	// 菜单挂载模块
	s.Mount(
		dashboard,
		NewFloder("系统管理", "system", "fa fa-cog", 10000).AddModule(
			userservice,
			roleModule,
			dictService,
		),
	)
}

func (s *Site) PermTree(ctx *AdminContext) {
	if s.Modules == nil {
		ctx.Fail("没有注册资源")
		return
	}
	resources := make([]Resource, 0)
	for _, module := range s.Modules {
		parent := module.GetResource()
		if floder, ok := module.(IFloder); ok {
			for _, c_module := range floder.GetChildren() {
				child := c_module.GetResource()
				for _, perm := range child.PermList {
					child.Children = append(child.Children, Resource{
						Label: perm.Label,
						Name:  perm.Code,
					})
				}
				parent.Children = append(parent.Children, child)
			}
		} else {
			for _, perm := range parent.PermList {
				parent.Children = append(parent.Children, Resource{
					Label: perm.Label,
					Name:  perm.Code,
				})
			}
		}
		resources = append(resources, parent)
	}
	ctx.Sucess(resources, "")
}
